
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="zh_Hans">
  <head>
    <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>日志 &#8212; Django 3.2.11.dev 文档</title>
    <link rel="stylesheet" href="../_static/default.css" type="text/css" />
    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
    <script type="text/javascript" id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
    <script type="text/javascript" src="../_static/jquery.js"></script>
    <script type="text/javascript" src="../_static/underscore.js"></script>
    <script type="text/javascript" src="../_static/doctools.js"></script>
    <script type="text/javascript" src="../_static/language_data.js"></script>
    <link rel="index" title="索引" href="../genindex.html" />
    <link rel="search" title="搜索" href="../search.html" />
    <link rel="next" title="分页" href="pagination.html" />
    <link rel="prev" title="Time zones" href="i18n/timezones.html" />



 
<script src="../templatebuiltins.js"></script>
<script>
(function($) {
    if (!django_template_builtins) {
       // templatebuiltins.js missing, do nothing.
       return;
    }
    $(document).ready(function() {
        // Hyperlink Django template tags and filters
        var base = "../ref/templates/builtins.html";
        if (base == "#") {
            // Special case for builtins.html itself
            base = "";
        }
        // Tags are keywords, class '.k'
        $("div.highlight\\-html\\+django span.k").each(function(i, elem) {
             var tagname = $(elem).text();
             if ($.inArray(tagname, django_template_builtins.ttags) != -1) {
                 var fragment = tagname.replace(/_/, '-');
                 $(elem).html("<a href='" + base + "#" + fragment + "'>" + tagname + "</a>");
             }
        });
        // Filters are functions, class '.nf'
        $("div.highlight\\-html\\+django span.nf").each(function(i, elem) {
             var filtername = $(elem).text();
             if ($.inArray(filtername, django_template_builtins.tfilters) != -1) {
                 var fragment = filtername.replace(/_/, '-');
                 $(elem).html("<a href='" + base + "#" + fragment + "'>" + filtername + "</a>");
             }
        });
    });
})(jQuery);</script>

  </head><body>

    <div class="document">
  <div id="custom-doc" class="yui-t6">
    <div id="hd">
      <h1><a href="../index.html">Django 3.2.11.dev 文档</a></h1>
      <div id="global-nav">
        <a title="Home page" href="../index.html">Home</a>  |
        <a title="Table of contents" href="../contents.html">Table of contents</a>  |
        <a title="Global index" href="../genindex.html">Index</a>  |
        <a title="Module index" href="../py-modindex.html">Modules</a>
      </div>
      <div class="nav">
    &laquo; <a href="i18n/timezones.html" title="Time zones">previous</a>
     |
    <a href="index.html" title="使用 Django" accesskey="U">up</a>
   |
    <a href="pagination.html" title="分页">next</a> &raquo;</div>
    </div>

    <div id="bd">
      <div id="yui-main">
        <div class="yui-b">
          <div class="yui-g" id="topics-logging">
            
  <div class="section" id="s-module-django.utils.log">
<span id="s-logging"></span><span id="module-django.utils.log"></span><span id="logging"></span><h1>日志<a class="headerlink" href="#module-django.utils.log" title="永久链接至标题">¶</a></h1>
<div class="section" id="s-a-quick-logging-primer">
<span id="a-quick-logging-primer"></span><h2>日志管理快速入门<a class="headerlink" href="#a-quick-logging-primer" title="永久链接至标题">¶</a></h2>
<p>Django 使用 Python 内置的 <a class="reference external" href="https://docs.python.org/3/library/logging.html#module-logging" title="(在 Python v3.10)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">logging</span></code></a> 模块处理系统日志。关于该模块的使用，Python 文档里有更详细的讨论。不过，如果你从未用过 Python 的 logging 框架（或者即便你用过），这里是一篇快速入门。</p>
<div class="section" id="s-the-cast-of-players">
<span id="the-cast-of-players"></span><h3>日志框架的组成元素<a class="headerlink" href="#the-cast-of-players" title="永久链接至标题">¶</a></h3>
<p>一份 Python logging 配置有下面四个部分组成：</p>
<ul class="simple">
<li><a class="reference internal" href="#topic-logging-parts-loggers"><span class="std std-ref">Loggers</span></a></li>
<li><a class="reference internal" href="#topic-logging-parts-handlers"><span class="std std-ref">Handlers</span></a></li>
<li><a class="reference internal" href="#topic-logging-parts-filters"><span class="std std-ref">过滤器</span></a></li>
<li><a class="reference internal" href="#topic-logging-parts-formatters"><span class="std std-ref">Formatters</span></a></li>
</ul>
<div class="section" id="s-loggers">
<span id="s-topic-logging-parts-loggers"></span><span id="loggers"></span><span id="topic-logging-parts-loggers"></span><h4>Loggers<a class="headerlink" href="#loggers" title="永久链接至标题">¶</a></h4>
<p>logger 是日志系统的入口。每个 logger 都是命名了的 bucket， 消息写入 bucket 以便进一步处理。</p>
<p>logger 可以配置 <em>日志级别</em>。日志级别描述了由该 logger 处理的消息的严重性。Python 定义了下面几种日志级别：</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">DEBUG</span></code>：排查故障时使用的低级别系统信息</li>
<li><code class="docutils literal notranslate"><span class="pre">INFO</span></code>：一般的系统信息</li>
<li><code class="docutils literal notranslate"><span class="pre">WARNING</span></code>：描述系统发生了一些小问题的信息</li>
<li><code class="docutils literal notranslate"><span class="pre">ERROR</span></code>：描述系统发生了大问题的信息</li>
<li><code class="docutils literal notranslate"><span class="pre">CRITICAL</span></code>：描述系统发生严重问题的信息</li>
</ul>
<p>每一条写入 logger 的消息都是一条 <em>日志记录</em>。每一条日志记录也包含 <em>日志级别</em>，代表对应消息的严重程度。日志记录还包含有用的元数据，来描述被记录了日志的事件细节，例如堆栈跟踪或者错误码。</p>
<p>当 logger 处理一条消息时，会将自己的日志级别和这条消息的日志级别做对比。如果消息的日志级别匹配或者高于 logger 的日志级别，它就会被进一步处理。否则这条消息就会被忽略掉。</p>
<p>当 logger 确定了一条消息需要处理之后，会把它传给 <em>Handler</em>。</p>
</div>
<div class="section" id="s-handlers">
<span id="s-topic-logging-parts-handlers"></span><span id="handlers"></span><span id="topic-logging-parts-handlers"></span><h4>Handlers<a class="headerlink" href="#handlers" title="永久链接至标题">¶</a></h4>
<p>Handler 是决定如何处理 logger 中每一条消息的引擎。它描述特定的日志行为，比如把消息输出到屏幕、文件或网络 socket。</p>
<p>和 logger 一样，handler 也有日志级别的概念。如果一条日志记录的级别不匹配或者低于 handler 的日志级别，对应的消息会被 handler 忽略。</p>
<p>一个 logger 可以有多个 handler，每一个 handler 可以有不同的日志级别。这样就可以根据消息的重要性不同，来提供不同格式的输出。例如，你可以添加一个 handler 把  <code class="docutils literal notranslate"><span class="pre">ERROR</span></code> 和 <code class="docutils literal notranslate"><span class="pre">CRITICAL</span></code>&nbsp;消息发到寻呼机，再添加另一个 handler 把所有的消息（包括 <code class="docutils literal notranslate"><span class="pre">ERROR</span></code> 和 <code class="docutils literal notranslate"><span class="pre">CRITICAL</span></code> 消息）保存到文件里以便日后分析。</p>
</div>
<div class="section" id="s-filters">
<span id="s-topic-logging-parts-filters"></span><span id="filters"></span><span id="topic-logging-parts-filters"></span><h4>过滤器<a class="headerlink" href="#filters" title="永久链接至标题">¶</a></h4>
<p>在日志记录从 logger 传到 handler 的过程中，使用 Filter 来做额外的控制。</p>
<p>默认情况下，只要级别匹配，任何日志消息都会被处理。不过，也可以通过添加 filter 来给日志处理的过程增加额外条件。例如，可以添加一个 filter 只允许某个特定来源的 <code class="docutils literal notranslate"><span class="pre">ERROR</span></code> 消息输出。</p>
<p>Filter 还被用来在日志输出之前对日志记录做修改。例如，可以写一个 filter，当满足一定条件时，把日志记录从 <code class="docutils literal notranslate"><span class="pre">ERROR</span></code> 降到 <code class="docutils literal notranslate"><span class="pre">WARNING</span></code> 级别。</p>
<p>Filter 在 logger 和 handler 中都可以添加；多个 filter 可以链接起来使用，来做多重过滤操作。</p>
</div>
<div class="section" id="s-formatters">
<span id="s-topic-logging-parts-formatters"></span><span id="formatters"></span><span id="topic-logging-parts-formatters"></span><h4>Formatters<a class="headerlink" href="#formatters" title="永久链接至标题">¶</a></h4>
<p>日志记录最终是需要以文本来呈现的。Formatter 描述了文本的格式。一个 formatter 通常由包含 <a class="reference external" href="https://docs.python.org/3/library/logging.html#logrecord-attributes" title="(在 Python v3.10)"><span class="xref std std-ref">LogRecord attributes</span></a> 的 Python 格式化字符串组成，不过你也可以为特定的格式来配置自定义的 formatter。</p>
</div>
</div>
</div>
<div class="section" id="s-using-logging">
<span id="using-logging"></span><h2>使用 logging 模块<a class="headerlink" href="#using-logging" title="永久链接至标题">¶</a></h2>
<p>一旦你配置了你的记录器、处理程序、过滤器和格式化程序，你就需要将记录调用放入你的代码中。使用日志框架的工作原理是这样的：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># import the logging library</span>
<span class="kn">import</span> <span class="nn">logging</span>

<span class="c1"># Get an instance of a logger</span>
<span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="vm">__name__</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">my_view</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">arg1</span><span class="p">,</span> <span class="n">arg</span><span class="p">):</span>
    <span class="o">...</span>
    <span class="k">if</span> <span class="n">bad_mojo</span><span class="p">:</span>
        <span class="c1"># Log an error message</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s1">&#39;Something went wrong!&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>就这么简单！<code class="docutils literal notranslate"><span class="pre">bad_mojo</span></code> 条件每次满足都会写一条 error 日志。</p>
<div class="section" id="s-naming-loggers">
<span id="naming-loggers"></span><h3>为 logger 命名<a class="headerlink" href="#naming-loggers" title="永久链接至标题">¶</a></h3>
<p>对 <a class="reference external" href="https://docs.python.org/3/library/logging.html#logging.getLogger" title="(在 Python v3.10)"><code class="xref py py-func docutils literal notranslate"><span class="pre">logging.getLogger()</span></code></a> 的调用会获取（必要时会创建）一个 logger 的实例。不同的 logger 实例用名字来区分。这个名字是为了在配置的时候指定 logger。</p>
<p>按照惯例，logger 的名字通常是包含该 logger 的 Python 模块名，即  <code class="docutils literal notranslate"><span class="pre">__name__</span></code>。这样可以基于模块来过滤和处理日志请求。不过，如果你有其他的方式来组织你的日志消息，可以为 logger 提供点号分割的名字来标识它：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Get an instance of a specific named logger</span>
<span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s1">&#39;project.interesting.stuff&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>这种 logger 的名字，用点号分隔的路径定义了一种层次结构。<code class="docutils literal notranslate"><span class="pre">project.interesting</span></code> 这个 logger 是 <code class="docutils literal notranslate"><span class="pre">project.interesting.stuff</span></code> logger 的上级；而 <code class="docutils literal notranslate"><span class="pre">project</span></code> logger 是 <code class="docutils literal notranslate"><span class="pre">project.interesting</span></code> logger 的上级。</p>
<p>为什么层次结构很重要？嗯，因为记录器可以被设置为将其记录调用 <em>传播</em> 到其父级。通过这种方式，你可以在记录器树的根部定义一组处理程序，并捕获记录器子树中的所有记录调用。在 <code class="docutils literal notranslate"><span class="pre">project</span></code> 命名空间中定义的日志记录器将捕获在 <code class="docutils literal notranslate"><span class="pre">project.interest</span></code> 和 <code class="docutils literal notranslate"><span class="pre">project.interest.stuff</span></code> 日志记录器上发出的所有日志记录消息。</p>
<p>可以基于 logger 来控制传播的行为。 如果你不希望某个 logger 传播给上级，可以关闭它。</p>
</div>
<div class="section" id="s-making-logging-calls">
<span id="making-logging-calls"></span><h3>发起 logging 调用<a class="headerlink" href="#making-logging-calls" title="永久链接至标题">¶</a></h3>
<p>logger 实例包含了每种默认日志级别的入口方法：</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">logger.debug()</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">logger.info()</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">logger.warning()</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">logger.error()</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">logger.critical()</span></code></li>
</ul>
<p>还有两种其他的调用方法：</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">logger.log()</span></code>：手动输出一条指定日志级别的日志消息。</li>
<li><code class="docutils literal notranslate"><span class="pre">logger.exception()</span></code>：创建一个包含当前异常堆栈帧的 <code class="docutils literal notranslate"><span class="pre">ERROR</span></code> 级别日志消息。</li>
</ul>
</div>
</div>
<div class="section" id="s-configuring-logging">
<span id="s-id1"></span><span id="configuring-logging"></span><span id="id1"></span><h2>日志模块的配置<a class="headerlink" href="#configuring-logging" title="永久链接至标题">¶</a></h2>
<p>仅仅在代码中加入日志调用是不够的。你还需要配置日志记录器、处理程序、过滤器和格式化程序，以确保你能使用日志输出。</p>
<p>Python 的日志库提供了一些配置方法，可以使用编程接口或者配置文件。Django默认使用 <a class="reference external" href="https://docs.python.org/3/library/logging.config.html#logging-config-dictschema" title="(在 Python v3.10)"><span class="xref std std-ref">dictConfig format</span></a>。</p>
<p>In order to configure logging, you use <a class="reference internal" href="../ref/settings.html#std:setting-LOGGING"><code class="xref std std-setting docutils literal notranslate"><span class="pre">LOGGING</span></code></a> to define a
dictionary of logging settings. These settings describe the loggers,
handlers, filters and formatters that you want in your logging setup,
and the log levels and other properties that you want those components
to have.</p>
<p>默认情况下 <a class="reference internal" href="../ref/settings.html#std:setting-LOGGING"><code class="xref std std-setting docutils literal notranslate"><span class="pre">LOGGING</span></code></a> 配置和 <a class="reference internal" href="#default-logging-configuration"><span class="std std-ref">Django 默认日志配置</span></a>  按照下面的方式合并在一起：</p>
<p>如果 <a class="reference internal" href="../ref/settings.html#std:setting-LOGGING"><code class="xref std std-setting docutils literal notranslate"><span class="pre">LOGGING</span></code></a> dictConfig 中的 <code class="docutils literal notranslate"><span class="pre">disable_existing_loggers</span></code> 键被设置为 <code class="docutils literal notranslate"><span class="pre">True</span></code> （如果该键缺失，则为 <code class="docutils literal notranslate"><span class="pre">dictConfig</span></code> 默认值），则默认配置中的所有记录器都将被禁用。禁用的记录器与删除的记录器不同；记录器仍将存在，但会默默地丢弃任何记录到它的内容，甚至不会将条目传播到父记录仪。因此，你应该非常小心地使用 <code class="docutils literal notranslate"><span class="pre">'disable_existing_loggers':</span> <span class="pre">True</span></code>；这可能不是你想要的。相反，你可以将 <code class="docutils literal notranslate"><span class="pre">disable_existing_loggers</span></code> 设置为 <code class="docutils literal notranslate"><span class="pre">False</span></code>，然后重新定义一些或所有的默认日志记录器；或者你可以将 <a class="reference internal" href="../ref/settings.html#std:setting-LOGGING_CONFIG"><code class="xref std std-setting docutils literal notranslate"><span class="pre">LOGGING_CONFIG</span></code></a> 设置为 <code class="docutils literal notranslate"><span class="pre">None</span></code>，然后 <a class="reference internal" href="#disabling-logging-configuration"><span class="std std-ref">自己处理日志配置</span></a>。</p>
<p>logging 被配置成了 Django  <code class="docutils literal notranslate"><span class="pre">setup()</span></code> 函数的一部分。因此，你可以确定的是，logger 一直都可以在项目代码里使用。</p>
<div class="section" id="s-examples">
<span id="examples"></span><h3>示例<a class="headerlink" href="#examples" title="永久链接至标题">¶</a></h3>
<p><a class="reference external" href="https://docs.python.org/3/library/logging.config.html#logging-config-dictschema" title="(在 Python v3.10)"><span class="xref std std-ref">dictConfig format</span></a> 文档是获取日志配置细节的最好资料。不过，为了让你知道能做什么，下面有几个例子。</p>
<p>首先，这里有一个小配置，可以让你把所有的日志信息输出到控制台。</p>
<div class="literal-block-wrapper docutils container" id="id6">
<div class="code-block-caption"><span class="caption-text">settings.py</span><a class="headerlink" href="#id6" title="永久链接至代码">¶</a></div>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">os</span>

<span class="n">LOGGING</span> <span class="o">=</span> <span class="p">{</span>
    <span class="s1">&#39;version&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
    <span class="s1">&#39;disable_existing_loggers&#39;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
    <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">{</span>
        <span class="s1">&#39;console&#39;</span><span class="p">:</span> <span class="p">{</span>
            <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;logging.StreamHandler&#39;</span><span class="p">,</span>
        <span class="p">},</span>
    <span class="p">},</span>
    <span class="s1">&#39;root&#39;</span><span class="p">:</span> <span class="p">{</span>
        <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;console&#39;</span><span class="p">],</span>
        <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;WARNING&#39;</span><span class="p">,</span>
    <span class="p">},</span>
<span class="p">}</span>
</pre></div>
</div>
</div>
<p>这将配置父 <code class="docutils literal notranslate"><span class="pre">root</span></code> 记录器，以向控制台处理程序发送 <code class="docutils literal notranslate"><span class="pre">WARNING</span></code> 级别及以上的消息。通过将级别调整为 <code class="docutils literal notranslate"><span class="pre">INFO</span></code> 或 <code class="docutils literal notranslate"><span class="pre">DEBUG</span></code>，可以显示更多的消息。这在开发过程中可能很有用。</p>
<p>接下来我们可以添加更多细粒度的日志记录。下面是一个例子，说明如何让日志系统只从名为 logger 的 <a class="reference internal" href="#django-logger"><span class="std std-ref">django</span></a> 中打印更多的消息。</p>
<div class="literal-block-wrapper docutils container" id="id7">
<div class="code-block-caption"><span class="caption-text">settings.py</span><a class="headerlink" href="#id7" title="永久链接至代码">¶</a></div>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">os</span>

<span class="n">LOGGING</span> <span class="o">=</span> <span class="p">{</span>
    <span class="s1">&#39;version&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
    <span class="s1">&#39;disable_existing_loggers&#39;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
    <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">{</span>
        <span class="s1">&#39;console&#39;</span><span class="p">:</span> <span class="p">{</span>
            <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;logging.StreamHandler&#39;</span><span class="p">,</span>
        <span class="p">},</span>
    <span class="p">},</span>
    <span class="s1">&#39;root&#39;</span><span class="p">:</span> <span class="p">{</span>
        <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;console&#39;</span><span class="p">],</span>
        <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;WARNING&#39;</span><span class="p">,</span>
    <span class="p">},</span>
    <span class="s1">&#39;loggers&#39;</span><span class="p">:</span> <span class="p">{</span>
        <span class="s1">&#39;django&#39;</span><span class="p">:</span> <span class="p">{</span>
            <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;console&#39;</span><span class="p">],</span>
            <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s1">&#39;DJANGO_LOG_LEVEL&#39;</span><span class="p">,</span> <span class="s1">&#39;INFO&#39;</span><span class="p">),</span>
            <span class="s1">&#39;propagate&#39;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
        <span class="p">},</span>
    <span class="p">},</span>
<span class="p">}</span>
</pre></div>
</div>
</div>
<p>默认情况下，这个配置会从 <code class="docutils literal notranslate"><span class="pre">django</span></code> 的日志记录器中发送级别为 <code class="docutils literal notranslate"><span class="pre">INFO</span></code> 或更高的消息到控制台。这个级别和 Django 的默认日志配置是一样的，只是默认配置只在 <code class="docutils literal notranslate"><span class="pre">DEBUG=True</span></code> 时才显示日志记录。Django 不会记录很多这样的 <code class="docutils literal notranslate"><span class="pre">INFO</span></code> 级别的消息。不过，有了这个配置，你也可以设置环境变量 <code class="docutils literal notranslate"><span class="pre">DJANGO_LOG_LEVEL=DEBUG</span></code> 来查看 Django 所有的调试日志，因为它包括了所有的数据库查询，所以非常啰嗦。</p>
<p>你不需要把日志记录到控制台。下面是一个配置，它将所有来自 <a class="reference internal" href="#django-logger"><span class="std std-ref">django</span></a> 命名的记录器的日志记录写入本地文件。</p>
<div class="literal-block-wrapper docutils container" id="id8">
<div class="code-block-caption"><span class="caption-text">settings.py</span><a class="headerlink" href="#id8" title="永久链接至代码">¶</a></div>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">LOGGING</span> <span class="o">=</span> <span class="p">{</span>
    <span class="s1">&#39;version&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
    <span class="s1">&#39;disable_existing_loggers&#39;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
    <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">{</span>
        <span class="s1">&#39;file&#39;</span><span class="p">:</span> <span class="p">{</span>
            <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;DEBUG&#39;</span><span class="p">,</span>
            <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;logging.FileHandler&#39;</span><span class="p">,</span>
            <span class="s1">&#39;filename&#39;</span><span class="p">:</span> <span class="s1">&#39;/path/to/django/debug.log&#39;</span><span class="p">,</span>
        <span class="p">},</span>
    <span class="p">},</span>
    <span class="s1">&#39;loggers&#39;</span><span class="p">:</span> <span class="p">{</span>
        <span class="s1">&#39;django&#39;</span><span class="p">:</span> <span class="p">{</span>
            <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;file&#39;</span><span class="p">],</span>
            <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;DEBUG&#39;</span><span class="p">,</span>
            <span class="s1">&#39;propagate&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
        <span class="p">},</span>
    <span class="p">},</span>
<span class="p">}</span>
</pre></div>
</div>
</div>
<p>若你使用此例子，切记要将 <code class="docutils literal notranslate"><span class="pre">'filename'</span></code> 指向的路径改为当前运行 Django 应用的用户可写的路径。</p>
<p>最后，这里是一个相当复杂的日志设置的例子。</p>
<div class="literal-block-wrapper docutils container" id="id9">
<div class="code-block-caption"><span class="caption-text">settings.py</span><a class="headerlink" href="#id9" title="永久链接至代码">¶</a></div>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">LOGGING</span> <span class="o">=</span> <span class="p">{</span>
    <span class="s1">&#39;version&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
    <span class="s1">&#39;disable_existing_loggers&#39;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
    <span class="s1">&#39;formatters&#39;</span><span class="p">:</span> <span class="p">{</span>
        <span class="s1">&#39;verbose&#39;</span><span class="p">:</span> <span class="p">{</span>
            <span class="s1">&#39;format&#39;</span><span class="p">:</span> <span class="s1">&#39;</span><span class="si">{levelname}</span><span class="s1"> </span><span class="si">{asctime}</span><span class="s1"> </span><span class="si">{module}</span><span class="s1"> </span><span class="si">{process:d}</span><span class="s1"> </span><span class="si">{thread:d}</span><span class="s1"> </span><span class="si">{message}</span><span class="s1">&#39;</span><span class="p">,</span>
            <span class="s1">&#39;style&#39;</span><span class="p">:</span> <span class="s1">&#39;{&#39;</span><span class="p">,</span>
        <span class="p">},</span>
        <span class="s1">&#39;simple&#39;</span><span class="p">:</span> <span class="p">{</span>
            <span class="s1">&#39;format&#39;</span><span class="p">:</span> <span class="s1">&#39;</span><span class="si">{levelname}</span><span class="s1"> </span><span class="si">{message}</span><span class="s1">&#39;</span><span class="p">,</span>
            <span class="s1">&#39;style&#39;</span><span class="p">:</span> <span class="s1">&#39;{&#39;</span><span class="p">,</span>
        <span class="p">},</span>
    <span class="p">},</span>
    <span class="s1">&#39;filters&#39;</span><span class="p">:</span> <span class="p">{</span>
        <span class="s1">&#39;special&#39;</span><span class="p">:</span> <span class="p">{</span>
            <span class="s1">&#39;()&#39;</span><span class="p">:</span> <span class="s1">&#39;project.logging.SpecialFilter&#39;</span><span class="p">,</span>
            <span class="s1">&#39;foo&#39;</span><span class="p">:</span> <span class="s1">&#39;bar&#39;</span><span class="p">,</span>
        <span class="p">},</span>
        <span class="s1">&#39;require_debug_true&#39;</span><span class="p">:</span> <span class="p">{</span>
            <span class="s1">&#39;()&#39;</span><span class="p">:</span> <span class="s1">&#39;django.utils.log.RequireDebugTrue&#39;</span><span class="p">,</span>
        <span class="p">},</span>
    <span class="p">},</span>
    <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">{</span>
        <span class="s1">&#39;console&#39;</span><span class="p">:</span> <span class="p">{</span>
            <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;INFO&#39;</span><span class="p">,</span>
            <span class="s1">&#39;filters&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;require_debug_true&#39;</span><span class="p">],</span>
            <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;logging.StreamHandler&#39;</span><span class="p">,</span>
            <span class="s1">&#39;formatter&#39;</span><span class="p">:</span> <span class="s1">&#39;simple&#39;</span>
        <span class="p">},</span>
        <span class="s1">&#39;mail_admins&#39;</span><span class="p">:</span> <span class="p">{</span>
            <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;ERROR&#39;</span><span class="p">,</span>
            <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;django.utils.log.AdminEmailHandler&#39;</span><span class="p">,</span>
            <span class="s1">&#39;filters&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;special&#39;</span><span class="p">]</span>
        <span class="p">}</span>
    <span class="p">},</span>
    <span class="s1">&#39;loggers&#39;</span><span class="p">:</span> <span class="p">{</span>
        <span class="s1">&#39;django&#39;</span><span class="p">:</span> <span class="p">{</span>
            <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;console&#39;</span><span class="p">],</span>
            <span class="s1">&#39;propagate&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
        <span class="p">},</span>
        <span class="s1">&#39;django.request&#39;</span><span class="p">:</span> <span class="p">{</span>
            <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;mail_admins&#39;</span><span class="p">],</span>
            <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;ERROR&#39;</span><span class="p">,</span>
            <span class="s1">&#39;propagate&#39;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
        <span class="p">},</span>
        <span class="s1">&#39;myproject.custom&#39;</span><span class="p">:</span> <span class="p">{</span>
            <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;console&#39;</span><span class="p">,</span> <span class="s1">&#39;mail_admins&#39;</span><span class="p">],</span>
            <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;INFO&#39;</span><span class="p">,</span>
            <span class="s1">&#39;filters&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;special&#39;</span><span class="p">]</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
</div>
<p>该日志配置做了以下事情：</p>
<ul>
<li><p class="first">识别配置为 'dictConfig 版本 1' 格式。目前，这是唯一的 dictConfig 格式版本。</p>
</li>
<li><p class="first">定义两个格式化程序：</p>
<ul>
<li><p class="first"><code class="docutils literal notranslate"><span class="pre">simple</span></code>，输出日志级别名称（如 <code class="docutils literal notranslate"><span class="pre">DEBUG</span></code>）和日志信息。</p>
<p><code class="docutils literal notranslate"><span class="pre">format</span></code> 字符串是一个普通的 Python 格式化字符串，它描述了每个日志行要输出的细节。可以输出的完整细节列表可以在 <a class="reference external" href="https://docs.python.org/3/library/logging.html#formatter-objects" title="(在 Python v3.10)"><span>Formatter Objects</span></a> 中找到。</p>
</li>
<li><p class="first"><code class="docutils literal notranslate"><span class="pre">verbose</span></code>，输出日志级别名称、日志信息，以及生成日志信息的时间、进程、线程和模块。</p>
</li>
</ul>
</li>
<li><p class="first">定义两个过滤器：</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">project.logging.SpecialFilter</span></code>，使用别名 <code class="docutils literal notranslate"><span class="pre">special</span></code>。如果这个过滤器需要额外的参数，它们可以作为过滤器配置字典中的附加键提供。在这种情况下，当实例化 <code class="docutils literal notranslate"><span class="pre">SpecialFilter</span></code> 时，参数 <code class="docutils literal notranslate"><span class="pre">foo</span></code> 将被赋予一个 <code class="docutils literal notranslate"><span class="pre">bar</span></code> 的值。</li>
<li><code class="docutils literal notranslate"><span class="pre">django.utils.log.RequireDebugTrue</span></code>，当 <a class="reference internal" href="../ref/settings.html#std:setting-DEBUG"><code class="xref std std-setting docutils literal notranslate"><span class="pre">DEBUG</span></code></a> 为 <code class="docutils literal notranslate"><span class="pre">True</span></code> 时，传递记录。</li>
</ul>
</li>
<li><p class="first">定义两个处理程序：</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">console</span></code>，一个 <a class="reference external" href="https://docs.python.org/3/library/logging.handlers.html#logging.StreamHandler" title="(在 Python v3.10)"><code class="xref py py-class docutils literal notranslate"><span class="pre">StreamHandler</span></code></a>，它将任何 <code class="docutils literal notranslate"><span class="pre">INFO</span></code> （或更高）消息打印到 <code class="docutils literal notranslate"><span class="pre">sys.stderr</span></code>。该处理程序使用 <code class="docutils literal notranslate"><span class="pre">simple</span></code> 输出格式。</li>
<li><code class="docutils literal notranslate"><span class="pre">mail_admins</span></code>，一个 <a class="reference internal" href="#django.utils.log.AdminEmailHandler" title="django.utils.log.AdminEmailHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">AdminEmailHandler</span></code></a>，它向网站 <a class="reference internal" href="../ref/settings.html#std:setting-ADMINS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">ADMINS</span></code></a> 发送任何 <code class="docutils literal notranslate"><span class="pre">ERROR</span></code> （或更高）消息。该处理程序使用 <code class="docutils literal notranslate"><span class="pre">special</span></code> 过滤器。</li>
</ul>
</li>
<li><p class="first">配置三个记录器。</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">django</span></code>，将所有信息传递给 <code class="docutils literal notranslate"><span class="pre">console</span></code> 处理程序。</li>
<li><code class="docutils literal notranslate"><span class="pre">django.request</span></code>，它将所有 <code class="docutils literal notranslate"><span class="pre">ERROR</span></code> 消息传递给 <code class="docutils literal notranslate"><span class="pre">mail_admins</span></code> 处理程序。此外，这个记录器被标记为 <em>不</em> 传播消息。这意味着写给 <code class="docutils literal notranslate"><span class="pre">django.request</span></code> 的日志信息不会被 <code class="docutils literal notranslate"><span class="pre">django</span></code> 日志处理程序处理。</li>
<li><code class="docutils literal notranslate"><span class="pre">myproject.custom</span></code>，它将所有 <code class="docutils literal notranslate"><span class="pre">INFO</span></code> 或更高等级的消息传递给两个处理程序——<code class="docutils literal notranslate"><span class="pre">console</span></code> 和 <code class="docutils literal notranslate"><span class="pre">mail_admins</span></code>。这意味着所有 <code class="docutils literal notranslate"><span class="pre">INFO</span></code> 级别（或更高）的消息将被打印到控制台；<code class="docutils literal notranslate"><span class="pre">ERROR</span></code> 和 <code class="docutils literal notranslate"><span class="pre">CRITICAL</span></code> 消息也将通过电子邮件输出。</li>
</ul>
</li>
</ul>
</div>
<div class="section" id="s-custom-logging-configuration">
<span id="custom-logging-configuration"></span><h3>自定义日志记录配置<a class="headerlink" href="#custom-logging-configuration" title="永久链接至标题">¶</a></h3>
<p>如果你不想使用 Python 的 dictConfig 格式来配置记录器，你可以指定自己的配置方案。</p>
<p><a class="reference internal" href="../ref/settings.html#std:setting-LOGGING_CONFIG"><code class="xref std std-setting docutils literal notranslate"><span class="pre">LOGGING_CONFIG</span></code></a> 设置定义了用于配置 Django 日志记录器的可调用对象，默认情况下，它指向 Python 的 <a class="reference external" href="https://docs.python.org/3/library/logging.config.html#logging.config.dictConfig" title="(在 Python v3.10)"><code class="xref py py-func docutils literal notranslate"><span class="pre">logging.config.dictConfig()</span></code></a> 函数。然而，如果你想使用不同的配置过程，你可以使用其他任何一个接受单一参数的可调用。当配置日志时， <a class="reference internal" href="../ref/settings.html#std:setting-LOGGING"><code class="xref std std-setting docutils literal notranslate"><span class="pre">LOGGING</span></code></a> 的内容将作为该参数的值提供。</p>
</div>
<div class="section" id="s-disabling-logging-configuration">
<span id="s-id2"></span><span id="disabling-logging-configuration"></span><span id="id2"></span><h3>禁用日志记录配置<a class="headerlink" href="#disabling-logging-configuration" title="永久链接至标题">¶</a></h3>
<p>如果你根本不想配置日志记录（或者你想用自己的方法手动配置日志记录），你可以将 <a class="reference internal" href="../ref/settings.html#std:setting-LOGGING_CONFIG"><code class="xref std std-setting docutils literal notranslate"><span class="pre">LOGGING_CONFIG</span></code></a> 设置为 <code class="docutils literal notranslate"><span class="pre">None</span></code>。这将禁用 <a class="reference internal" href="#default-logging-configuration"><span class="std std-ref">Django 的默认日志记录</span></a> 的配置过程。</p>
<p>将 <a class="reference internal" href="../ref/settings.html#std:setting-LOGGING_CONFIG"><code class="xref std std-setting docutils literal notranslate"><span class="pre">LOGGING_CONFIG</span></code></a> 设置为 <code class="docutils literal notranslate"><span class="pre">None</span></code> 只是意味着自动配置过程被禁用，而不是日志本身。如果你禁用了配置过程，Django 仍然会进行日志调用，回到默认的日志行为。</p>
<p>下面是一个禁用 Django 的日志配置，然后手动配置日志的例子。</p>
<div class="literal-block-wrapper docutils container" id="id10">
<div class="code-block-caption"><span class="caption-text">settings.py</span><a class="headerlink" href="#id10" title="永久链接至代码">¶</a></div>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">LOGGING_CONFIG</span> <span class="o">=</span> <span class="kc">None</span>

<span class="kn">import</span> <span class="nn">logging.config</span>
<span class="n">logging</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">dictConfig</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
</pre></div>
</div>
</div>
<p>请注意，默认的配置过程只有在设置完全加载后才会调用 <a class="reference internal" href="../ref/settings.html#std:setting-LOGGING_CONFIG"><code class="xref std std-setting docutils literal notranslate"><span class="pre">LOGGING_CONFIG</span></code></a>。相反，在设置文件中手动配置日志记录将立即加载你的日志记录配置。因此，你的日志配置必须出现在它所依赖的任何设置之后。</p>
</div>
</div>
<div class="section" id="s-django-s-logging-extensions">
<span id="django-s-logging-extensions"></span><h2>Django 的日志记录扩展<a class="headerlink" href="#django-s-logging-extensions" title="永久链接至标题">¶</a></h2>
<p>Django 提供了一些实用工具来处理 Web 服务器环境中的独特的日志记录需求。</p>
<div class="section" id="s-id3">
<span id="id3"></span><h3>Loggers<a class="headerlink" href="#id3" title="永久链接至标题">¶</a></h3>
<p>Django 提供了几种内置的记录器。</p>
<div class="section" id="s-django">
<span id="s-django-logger"></span><span id="django"></span><span id="django-logger"></span><h4><code class="docutils literal notranslate"><span class="pre">django</span></code><a class="headerlink" href="#django" title="永久链接至标题">¶</a></h4>
<p><code class="docutils literal notranslate"><span class="pre">django</span></code> 层次结构中消息的总记录器。不使用该名称发布消息，而是使用以下记录器之一。</p>
</div>
<div class="section" id="s-django-request">
<span id="s-django-request-logger"></span><span id="django-request"></span><span id="django-request-logger"></span><h4><code class="docutils literal notranslate"><span class="pre">django.request</span></code><a class="headerlink" href="#django-request" title="永久链接至标题">¶</a></h4>
<p>记录与处理请求有关的信息。5XX 的响应以 <code class="docutils literal notranslate"><span class="pre">ERROR</span></code> 消息的形式出现；4XX 的响应以 <code class="docutils literal notranslate"><span class="pre">WARNING</span></code> 消息的形式出现。记录在 <code class="docutils literal notranslate"><span class="pre">django.security</span></code> 记录器中的请求不会记录在 <code class="docutils literal notranslate"><span class="pre">django.request</span></code> 中。</p>
<p>发送给此记录器的消息有以下额外的上下文：</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">status_code</span></code>：与请求相关的 HTTP 响应代码。</li>
<li><code class="docutils literal notranslate"><span class="pre">request</span></code>：产生记录信息的请求对象。</li>
</ul>
</div>
<div class="section" id="s-django-server">
<span id="s-django-server-logger"></span><span id="django-server"></span><span id="django-server-logger"></span><h4><code class="docutils literal notranslate"><span class="pre">django.server</span></code><a class="headerlink" href="#django-server" title="永久链接至标题">¶</a></h4>
<p>记录与处理由 <a class="reference internal" href="../ref/django-admin.html#django-admin-runserver"><code class="xref std std-djadmin docutils literal notranslate"><span class="pre">runserver</span></code></a> 命令调用的服务器收到的请求有关的消息。HTTP 5XX 响应被记录为 <code class="docutils literal notranslate"><span class="pre">ERROR</span></code> 消息，4XX 响应被记录为 <code class="docutils literal notranslate"><span class="pre">WARNING</span></code> 消息，其他所有消息被记录为 <code class="docutils literal notranslate"><span class="pre">INFO</span></code>。</p>
<p>发送给此记录器的消息有以下额外的上下文：</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">status_code</span></code>：与请求相关的 HTTP 响应代码。</li>
<li><code class="docutils literal notranslate"><span class="pre">request</span></code>：产生记录信息的请求对象。</li>
</ul>
</div>
<div class="section" id="s-django-template">
<span id="s-django-template-logger"></span><span id="django-template"></span><span id="django-template-logger"></span><h4><code class="docutils literal notranslate"><span class="pre">django.template</span></code><a class="headerlink" href="#django-template" title="永久链接至标题">¶</a></h4>
<p>记录与模板渲染相关的消息。</p>
<ul class="simple">
<li>缺少的上下文变量会被记录为 <code class="docutils literal notranslate"><span class="pre">DEBUG</span></code> 消息。</li>
</ul>
</div>
<div class="section" id="s-django-db-backends">
<span id="s-django-db-logger"></span><span id="django-db-backends"></span><span id="django-db-logger"></span><h4><code class="docutils literal notranslate"><span class="pre">django.db.backends</span></code><a class="headerlink" href="#django-db-backends" title="永久链接至标题">¶</a></h4>
<p>与代码与数据库互动有关的信息。例如，请求执行的每一条应用程序级别的 SQL 语句都会以 <code class="docutils literal notranslate"><span class="pre">DEBUG</span></code> 级别记录到这个记录器。</p>
<p>发送给此记录器的消息有以下额外的上下文：</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">duration</span></code>：执行 SQL 语句所需时间。</li>
<li><code class="docutils literal notranslate"><span class="pre">sql</span></code>：所执行的 SQL 语句。</li>
<li><code class="docutils literal notranslate"><span class="pre">params</span></code>：SQL 调用中使用的参数。</li>
</ul>
<p>出于性能考虑，只有当 <code class="docutils literal notranslate"><span class="pre">settings.DEBUG</span></code> 设置为 <code class="docutils literal notranslate"><span class="pre">True</span></code> 时，才会启用 SQL 日志记录，而不考虑日志级别或安装的处理程序。</p>
<p>该日志不包括框架级初始化（如 <code class="docutils literal notranslate"><span class="pre">SET</span> <span class="pre">TIMEZONE</span></code>）或事务管理查询（如 <code class="docutils literal notranslate"><span class="pre">BEGIN</span></code>、<code class="docutils literal notranslate"><span class="pre">COMMIT</span></code> 和 <code class="docutils literal notranslate"><span class="pre">ROLLBACK</span></code>）。如果想查看所有数据库查询，请在数据库中开启查询记录。</p>
</div>
<div class="section" id="s-django-security">
<span id="s-django-security-logger"></span><span id="django-security"></span><span id="django-security-logger"></span><h4><code class="docutils literal notranslate"><span class="pre">django.security.*</span></code><a class="headerlink" href="#django-security" title="永久链接至标题">¶</a></h4>
<p>安全记录器将接收任何发生 <a class="reference internal" href="../ref/exceptions.html#django.core.exceptions.SuspiciousOperation" title="django.core.exceptions.SuspiciousOperation"><code class="xref py py-exc docutils literal notranslate"><span class="pre">SuspiciousOperation</span></code></a> 和其他安全相关错误的消息。每个子类型的安全错误都有一个子记录器，包括所有 <code class="docutils literal notranslate"><span class="pre">SuspiciousOperation</span></code>s。日志事件的级别取决于异常处理的位置。 大多数发生的事件被记录为警告，而任何到达 WSGI 处理程序的 <code class="docutils literal notranslate"><span class="pre">SuspiciousOperation</span></code> 将被记录为错误。例如，当客户端的请求中包含一个 HTTP <code class="docutils literal notranslate"><span class="pre">Host</span></code> 头，而这个头不符合 <a class="reference internal" href="../ref/settings.html#std:setting-ALLOWED_HOSTS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">ALLOWED_HOSTS</span></code></a> 时，Django 会返回一个 400 的响应，并且错误信息会被记录到 <code class="docutils literal notranslate"><span class="pre">django.security.DisallowedHost</span></code> 记录器中。</p>
<p>这些日志事件默认会到达 <code class="docutils literal notranslate"><span class="pre">django</span></code> 日志器，当 <code class="docutils literal notranslate"><span class="pre">DEBUG=False</span></code> 时，记录器会将错误事件发送给管理员。由于 <code class="docutils literal notranslate"><span class="pre">SuspiciousOperation</span></code> 导致 400 响应的请求不会被记录到 <code class="docutils literal notranslate"><span class="pre">django.request</span></code> 记录器，而只会记录到 <code class="docutils literal notranslate"><span class="pre">django.security</span></code> 记录器。</p>
<p>要使某一特定类型的 <code class="docutils literal notranslate"><span class="pre">SuspiciousOperation</span></code> 保持沉默，你可以按照以下示例覆盖该特定的记录器：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">{</span>
    <span class="s1">&#39;null&#39;</span><span class="p">:</span> <span class="p">{</span>
        <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;logging.NullHandler&#39;</span><span class="p">,</span>
    <span class="p">},</span>
<span class="p">},</span>
<span class="s1">&#39;loggers&#39;</span><span class="p">:</span> <span class="p">{</span>
    <span class="s1">&#39;django.security.DisallowedHost&#39;</span><span class="p">:</span> <span class="p">{</span>
        <span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;null&#39;</span><span class="p">],</span>
        <span class="s1">&#39;propagate&#39;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
    <span class="p">},</span>
<span class="p">},</span>
</pre></div>
</div>
<p>其他不基于 <code class="docutils literal notranslate"><span class="pre">SuspiciousOperation</span></code> 的 <code class="docutils literal notranslate"><span class="pre">django.security</span></code> 记录器是：</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">django.security.csrf</span></code>：用于 <a class="reference internal" href="../ref/csrf.html#csrf-rejected-requests"><span class="std std-ref">CSRF 错误</span></a>。</li>
</ul>
</div>
<div class="section" id="s-django-db-backends-schema">
<span id="django-db-backends-schema"></span><h4><code class="docutils literal notranslate"><span class="pre">django.db.backends.schema</span></code><a class="headerlink" href="#django-db-backends-schema" title="永久链接至标题">¶</a></h4>
<p>记录 <a class="reference internal" href="migrations.html"><span class="doc">migrations framework</span></a> 对数据库进行模式变更时执行的 SQL 查询。请注意，它不会记录 <a class="reference internal" href="../ref/migration-operations.html#django.db.migrations.operations.RunPython" title="django.db.migrations.operations.RunPython"><code class="xref py py-class docutils literal notranslate"><span class="pre">RunPython</span></code></a> 执行的查询。给这个记录器的消息在其额外的上下文中有 <code class="docutils literal notranslate"><span class="pre">params</span></code> 和 <code class="docutils literal notranslate"><span class="pre">sql</span></code> （但与 <code class="docutils literal notranslate"><span class="pre">django.db.backends</span></code> 不同，不是 duration）。这些值的含义与 <a class="reference internal" href="#django-db-logger"><span class="std std-ref">django.db.backends</span></a> 中的解释相同。</p>
</div>
</div>
<div class="section" id="s-id4">
<span id="id4"></span><h3>Handlers<a class="headerlink" href="#id4" title="永久链接至标题">¶</a></h3>
<p>除了 Python 日志模块提供的日志处理程序外，Django 还提供了一个日志处理程序。</p>
<dl class="class">
<dt id="django.utils.log.AdminEmailHandler">
<em class="property">class </em><code class="descname">AdminEmailHandler</code>(<em>include_html=False</em>, <em>email_backend=None</em>, <em>reporter_class=None</em>)<a class="headerlink" href="#django.utils.log.AdminEmailHandler" title="永久链接至目标">¶</a></dt>
<dd><p>该处理程序对收到的每条日志消息都会向站点 <a class="reference internal" href="../ref/settings.html#std:setting-ADMINS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">ADMINS</span></code></a> 发送一封邮件。</p>
<p>如果日志记录中包含 <code class="docutils literal notranslate"><span class="pre">request</span></code> 属性，电子邮件中会包含请求的全部细节。如果客户的 IP 地址在 <a class="reference internal" href="../ref/settings.html#std:setting-INTERNAL_IPS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">INTERNAL_IPS</span></code></a> 设置中，电子邮件主题将包括“内部 IP”；如果没有，则包括“外部 IP”。</p>
<p>如果日志记录中包含堆栈跟踪信息，该堆栈跟踪信息将包含在电子邮件中。</p>
<p><code class="docutils literal notranslate"><span class="pre">AdminEmailHandler</span></code> 的 <code class="docutils literal notranslate"><span class="pre">include_html</span></code> 参数用于控制回溯邮件是否包含一个 HTML 附件，该附件包含调试网页的完整内容，如果 <a class="reference internal" href="../ref/settings.html#std:setting-DEBUG"><code class="xref std std-setting docutils literal notranslate"><span class="pre">DEBUG</span></code></a> 为 <code class="docutils literal notranslate"><span class="pre">True</span></code> 的话，该附件将被生成。要在你的配置中设置这个值，请在 <code class="docutils literal notranslate"><span class="pre">django.utils.log.AdminEmailHandler</span></code> 的处理程序定义中包含它，就像这样：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">{</span>
    <span class="s1">&#39;mail_admins&#39;</span><span class="p">:</span> <span class="p">{</span>
        <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;ERROR&#39;</span><span class="p">,</span>
        <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;django.utils.log.AdminEmailHandler&#39;</span><span class="p">,</span>
        <span class="s1">&#39;include_html&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
    <span class="p">}</span>
<span class="p">},</span>
</pre></div>
</div>
<p>请注意，这封 HTML 版本的邮件包含了完整的跟踪信息，包括堆栈中每一层的本地变量的名称和值，以及你的Django设置值。这些信息可能非常敏感，你可能不想通过邮件发送。可以考虑使用诸如 <a class="reference external" href="https://pypi.org/project/sentry/">Sentry</a>  这样的软件来获得两全其美的效果--既能获得丰富的信息，又能保证不通过邮件发送信息的安全性。你也可以明确指定某些敏感信息从错误报告中过滤出来——在 <a class="reference internal" href="../howto/error-reporting.html#filtering-error-reports"><span class="std std-ref">过滤错误报告</span></a> 中了解更多信息。</p>
<p>通过设置 <code class="docutils literal notranslate"><span class="pre">AdminEmailHandler</span></code> 的 <code class="docutils literal notranslate"><span class="pre">email_backend</span></code> 参数，处理程序使用的 <a class="reference internal" href="email.html#topic-email-backends"><span class="std std-ref">email 后端</span></a> 可以被覆盖，就像这样：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">{</span>
    <span class="s1">&#39;mail_admins&#39;</span><span class="p">:</span> <span class="p">{</span>
        <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;ERROR&#39;</span><span class="p">,</span>
        <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;django.utils.log.AdminEmailHandler&#39;</span><span class="p">,</span>
        <span class="s1">&#39;email_backend&#39;</span><span class="p">:</span> <span class="s1">&#39;django.core.mail.backends.filebased.EmailBackend&#39;</span><span class="p">,</span>
    <span class="p">}</span>
<span class="p">},</span>
</pre></div>
</div>
<p>默认情况下，将使用 <a class="reference internal" href="../ref/settings.html#std:setting-EMAIL_BACKEND"><code class="xref std std-setting docutils literal notranslate"><span class="pre">EMAIL_BACKEND</span></code></a> 中指定的电子邮件后端实例。</p>
<p><code class="docutils literal notranslate"><span class="pre">AdminEmailHandler</span></code> 的 <code class="docutils literal notranslate"><span class="pre">reporter_class</span></code> 参数允许提供一个 <code class="docutils literal notranslate"><span class="pre">django.view.debug.ExceptionReporter</span></code> 子类来自定义邮件正文中发送的回溯文本。你提供一个字符串的导入路径到你想使用的类，像这样：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">{</span>
    <span class="s1">&#39;mail_admins&#39;</span><span class="p">:</span> <span class="p">{</span>
        <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;ERROR&#39;</span><span class="p">,</span>
        <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;django.utils.log.AdminEmailHandler&#39;</span><span class="p">,</span>
        <span class="s1">&#39;include_html&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
        <span class="s1">&#39;reporter_class&#39;</span><span class="p">:</span> <span class="s1">&#39;somepackage.error_reporter.CustomErrorReporter&#39;</span>
    <span class="p">}</span>
<span class="p">},</span>
</pre></div>
</div>
<dl class="method">
<dt id="django.utils.log.AdminEmailHandler.send_mail">
<code class="descname">send_mail</code>(<em>subject</em>, <em>message</em>, <em>*args</em>, <em>**kwargs</em>)<a class="headerlink" href="#django.utils.log.AdminEmailHandler.send_mail" title="永久链接至目标">¶</a></dt>
<dd><p>向管理员用户发送邮件。要自定义这个行为，你可以将 <a class="reference internal" href="#django.utils.log.AdminEmailHandler" title="django.utils.log.AdminEmailHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">AdminEmailHandler</span></code></a> 类子类化，并覆盖这个方法。</p>
</dd></dl>

</dd></dl>

</div>
<div class="section" id="s-id5">
<span id="id5"></span><h3>过滤器<a class="headerlink" href="#id5" title="永久链接至标题">¶</a></h3>
<p>除了 Python 日志模块提供的日志过滤器外，Django 还提供了一些日志过滤器。</p>
<dl class="class">
<dt id="django.utils.log.CallbackFilter">
<em class="property">class </em><code class="descname">CallbackFilter</code>(<em>callback</em>)<a class="headerlink" href="#django.utils.log.CallbackFilter" title="永久链接至目标">¶</a></dt>
<dd><p>这个过滤器接受一个回调函数（它应该接受一个单一的参数，即要记录的记录），并对每个通过过滤器的记录进行调用。如果回调函数返回 False，则不会对该记录进行处理。</p>
<p>例如，要从管理员邮件中过滤掉 <a class="reference internal" href="../ref/exceptions.html#django.http.UnreadablePostError" title="django.http.UnreadablePostError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">UnreadablePostError</span></code></a> （当用户取消上传时引发），你可以创建一个过滤函数：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.http</span> <span class="kn">import</span> <span class="n">UnreadablePostError</span>

<span class="k">def</span> <span class="nf">skip_unreadable_post</span><span class="p">(</span><span class="n">record</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">record</span><span class="o">.</span><span class="n">exc_info</span><span class="p">:</span>
        <span class="n">exc_type</span><span class="p">,</span> <span class="n">exc_value</span> <span class="o">=</span> <span class="n">record</span><span class="o">.</span><span class="n">exc_info</span><span class="p">[:</span><span class="mi">2</span><span class="p">]</span>
        <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">exc_value</span><span class="p">,</span> <span class="n">UnreadablePostError</span><span class="p">):</span>
            <span class="k">return</span> <span class="kc">False</span>
    <span class="k">return</span> <span class="kc">True</span>
</pre></div>
</div>
<p>然后将其添加到你的日志记录配置中：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="s1">&#39;filters&#39;</span><span class="p">:</span> <span class="p">{</span>
    <span class="s1">&#39;skip_unreadable_posts&#39;</span><span class="p">:</span> <span class="p">{</span>
        <span class="s1">&#39;()&#39;</span><span class="p">:</span> <span class="s1">&#39;django.utils.log.CallbackFilter&#39;</span><span class="p">,</span>
        <span class="s1">&#39;callback&#39;</span><span class="p">:</span> <span class="n">skip_unreadable_post</span><span class="p">,</span>
    <span class="p">}</span>
<span class="p">},</span>
<span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">{</span>
    <span class="s1">&#39;mail_admins&#39;</span><span class="p">:</span> <span class="p">{</span>
        <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;ERROR&#39;</span><span class="p">,</span>
        <span class="s1">&#39;filters&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;skip_unreadable_posts&#39;</span><span class="p">],</span>
        <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;django.utils.log.AdminEmailHandler&#39;</span>
    <span class="p">}</span>
<span class="p">},</span>
</pre></div>
</div>
</dd></dl>

<dl class="class">
<dt id="django.utils.log.RequireDebugFalse">
<em class="property">class </em><code class="descname">RequireDebugFalse</code><a class="headerlink" href="#django.utils.log.RequireDebugFalse" title="永久链接至目标">¶</a></dt>
<dd><p>只有当 settings.DEBUG 为 False 时，该过滤器才会传递记录。</p>
<p>该过滤器在默认的 <code class="xref std std-setting docutils literal notranslate"><span class="pre">logging</span></code> 配置中使用如下，以确保 <a class="reference internal" href="#django.utils.log.AdminEmailHandler" title="django.utils.log.AdminEmailHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">AdminEmailHandler</span></code></a> 只在 <a class="reference internal" href="../ref/settings.html#std:setting-DEBUG"><code class="xref std std-setting docutils literal notranslate"><span class="pre">DEBUG</span></code></a> 为 <code class="docutils literal notranslate"><span class="pre">False</span></code> 时向管理员发送错误邮件：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="s1">&#39;filters&#39;</span><span class="p">:</span> <span class="p">{</span>
    <span class="s1">&#39;require_debug_false&#39;</span><span class="p">:</span> <span class="p">{</span>
        <span class="s1">&#39;()&#39;</span><span class="p">:</span> <span class="s1">&#39;django.utils.log.RequireDebugFalse&#39;</span><span class="p">,</span>
    <span class="p">}</span>
<span class="p">},</span>
<span class="s1">&#39;handlers&#39;</span><span class="p">:</span> <span class="p">{</span>
    <span class="s1">&#39;mail_admins&#39;</span><span class="p">:</span> <span class="p">{</span>
        <span class="s1">&#39;level&#39;</span><span class="p">:</span> <span class="s1">&#39;ERROR&#39;</span><span class="p">,</span>
        <span class="s1">&#39;filters&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;require_debug_false&#39;</span><span class="p">],</span>
        <span class="s1">&#39;class&#39;</span><span class="p">:</span> <span class="s1">&#39;django.utils.log.AdminEmailHandler&#39;</span>
    <span class="p">}</span>
<span class="p">},</span>
</pre></div>
</div>
</dd></dl>

<dl class="class">
<dt id="django.utils.log.RequireDebugTrue">
<em class="property">class </em><code class="descname">RequireDebugTrue</code><a class="headerlink" href="#django.utils.log.RequireDebugTrue" title="永久链接至目标">¶</a></dt>
<dd><p>该过滤器类似于 <a class="reference internal" href="#django.utils.log.RequireDebugFalse" title="django.utils.log.RequireDebugFalse"><code class="xref py py-class docutils literal notranslate"><span class="pre">RequireDebugFalse</span></code></a>，但只有当 <a class="reference internal" href="../ref/settings.html#std:setting-DEBUG"><code class="xref std std-setting docutils literal notranslate"><span class="pre">DEBUG</span></code></a> 为 <code class="docutils literal notranslate"><span class="pre">True</span></code> 时才会传递记录。</p>
</dd></dl>

</div>
</div>
<div class="section" id="s-django-s-default-logging-configuration">
<span id="s-default-logging-configuration"></span><span id="django-s-default-logging-configuration"></span><span id="default-logging-configuration"></span><h2>Django 的默认日志配置<a class="headerlink" href="#django-s-default-logging-configuration" title="永久链接至标题">¶</a></h2>
<p>默认情况下，Django 配置了以下日志：</p>
<p>当 <a class="reference internal" href="../ref/settings.html#std:setting-DEBUG"><code class="xref std std-setting docutils literal notranslate"><span class="pre">DEBUG</span></code></a> 为 <code class="docutils literal notranslate"><span class="pre">True</span></code> 时：</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">django</span></code> 记录器将 <code class="docutils literal notranslate"><span class="pre">django</span></code> 层次结构（<code class="docutils literal notranslate"><span class="pre">django.server</span></code> 除外）中的 <code class="docutils literal notranslate"><span class="pre">INFO</span></code> 级别或更高的消息发送到控制台。</li>
</ul>
<p>当 <a class="reference internal" href="../ref/settings.html#std:setting-DEBUG"><code class="xref std std-setting docutils literal notranslate"><span class="pre">DEBUG</span></code></a> 为 <code class="docutils literal notranslate"><span class="pre">False</span></code> 时：</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">django</span></code> 记录器将 <code class="docutils literal notranslate"><span class="pre">django</span></code> 层次结构（<code class="docutils literal notranslate"><span class="pre">django.server</span></code> 除外）中带有 <code class="docutils literal notranslate"><span class="pre">ERROR</span></code> 或 <code class="docutils literal notranslate"><span class="pre">CRITICAL</span></code> 级别的消息发送到 <a class="reference internal" href="#django.utils.log.AdminEmailHandler" title="django.utils.log.AdminEmailHandler"><code class="xref py py-class docutils literal notranslate"><span class="pre">AdminEmailHandler</span></code></a>。</li>
</ul>
<p>与 <a class="reference internal" href="../ref/settings.html#std:setting-DEBUG"><code class="xref std std-setting docutils literal notranslate"><span class="pre">DEBUG</span></code></a> 的值无关。</p>
<ul class="simple">
<li><a class="reference internal" href="#django-server-logger"><span class="std std-ref">django.server</span></a> 记录器向控制台发送 <code class="docutils literal notranslate"><span class="pre">INFO</span></code> 或更高等级的消息。</li>
</ul>
<p>除了 <a class="reference internal" href="#django-server-logger"><span class="std std-ref">django.server</span></a> 之外，所有的日志记录器都会将日志记录传播给它们的父辈，直到 <code class="docutils literal notranslate"><span class="pre">django</span></code> 的根日志记录器。<code class="docutils literal notranslate"><span class="pre">console</span></code> 和 <code class="docutils literal notranslate"><span class="pre">mail_admins</span></code> 处理程序被附加到根记录器上，以提供上述行为。</p>
<p>还请参见 <a class="reference internal" href="#configuring-logging"><span class="std std-ref">配置日志</span></a> 了解如何补充或替换 <a class="reference external" href="https://github.com/django/django/blob/main/django/utils/log.py">django/utils/log.py</a> 中定义的默认日志配置。</p>
</div>
</div>


          </div>
        </div>
      </div>
      
        
          <div class="yui-b" id="sidebar">
            
      <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
        <div class="sphinxsidebarwrapper">
  <h3><a href="../contents.html">Table of Contents</a></h3>
  <ul>
<li><a class="reference internal" href="#">日志</a><ul>
<li><a class="reference internal" href="#a-quick-logging-primer">日志管理快速入门</a><ul>
<li><a class="reference internal" href="#the-cast-of-players">日志框架的组成元素</a><ul>
<li><a class="reference internal" href="#loggers">Loggers</a></li>
<li><a class="reference internal" href="#handlers">Handlers</a></li>
<li><a class="reference internal" href="#filters">过滤器</a></li>
<li><a class="reference internal" href="#formatters">Formatters</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#using-logging">使用 logging 模块</a><ul>
<li><a class="reference internal" href="#naming-loggers">为 logger 命名</a></li>
<li><a class="reference internal" href="#making-logging-calls">发起 logging 调用</a></li>
</ul>
</li>
<li><a class="reference internal" href="#configuring-logging">日志模块的配置</a><ul>
<li><a class="reference internal" href="#examples">示例</a></li>
<li><a class="reference internal" href="#custom-logging-configuration">自定义日志记录配置</a></li>
<li><a class="reference internal" href="#disabling-logging-configuration">禁用日志记录配置</a></li>
</ul>
</li>
<li><a class="reference internal" href="#django-s-logging-extensions">Django 的日志记录扩展</a><ul>
<li><a class="reference internal" href="#id3">Loggers</a><ul>
<li><a class="reference internal" href="#django"><code class="docutils literal notranslate"><span class="pre">django</span></code></a></li>
<li><a class="reference internal" href="#django-request"><code class="docutils literal notranslate"><span class="pre">django.request</span></code></a></li>
<li><a class="reference internal" href="#django-server"><code class="docutils literal notranslate"><span class="pre">django.server</span></code></a></li>
<li><a class="reference internal" href="#django-template"><code class="docutils literal notranslate"><span class="pre">django.template</span></code></a></li>
<li><a class="reference internal" href="#django-db-backends"><code class="docutils literal notranslate"><span class="pre">django.db.backends</span></code></a></li>
<li><a class="reference internal" href="#django-security"><code class="docutils literal notranslate"><span class="pre">django.security.*</span></code></a></li>
<li><a class="reference internal" href="#django-db-backends-schema"><code class="docutils literal notranslate"><span class="pre">django.db.backends.schema</span></code></a></li>
</ul>
</li>
<li><a class="reference internal" href="#id4">Handlers</a></li>
<li><a class="reference internal" href="#id5">过滤器</a></li>
</ul>
</li>
<li><a class="reference internal" href="#django-s-default-logging-configuration">Django 的默认日志配置</a></li>
</ul>
</li>
</ul>

  <h4>上一个主题</h4>
  <p class="topless"><a href="i18n/timezones.html"
                        title="上一章">Time zones</a></p>
  <h4>下一个主题</h4>
  <p class="topless"><a href="pagination.html"
                        title="下一章">分页</a></p>
  <div role="note" aria-label="source link">
    <h3>本页</h3>
    <ul class="this-page-menu">
      <li><a href="../_sources/topics/logging.txt"
            rel="nofollow">显示源代码</a></li>
    </ul>
   </div>
<div id="searchbox" style="display: none" role="search">
  <h3>快速搜索</h3>
    <div class="searchformwrapper">
    <form class="search" action="../search.html" method="get">
      <input type="text" name="q" />
      <input type="submit" value="转向" />
      <input type="hidden" name="check_keywords" value="yes" />
      <input type="hidden" name="area" value="default" />
    </form>
    </div>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
        </div>
      </div>
              <h3>Last update:</h3>
              <p class="topless">12月 07, 2021</p>
          </div>
        
      
    </div>

    <div id="ft">
      <div class="nav">
    &laquo; <a href="i18n/timezones.html" title="Time zones">previous</a>
     |
    <a href="index.html" title="使用 Django" accesskey="U">up</a>
   |
    <a href="pagination.html" title="分页">next</a> &raquo;</div>
    </div>
  </div>

      <div class="clearer"></div>
    </div>
  </body>
</html>